#include<cstdio>  
#include<unistd.h>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<string>
#include<sys/wait.h>
#include<fcntl.h>
using namespace std;

const int argvnum=128;
const int environnum=256;
const int commandnum=256;

char* g_argv[argvnum];//命令行参数表
int g_argc;

char* g_env[environnum];//低配环境变量表
extern char** environ;

bool is_redirect=false;//是不是重定向
string filename;//重定向文件名
string redirect;//重定向符号

void EnvironInit(){//初始化环境变量表
	int i;
	for(i=0;environ[i];i++){
		g_env[i]=new char[strlen(environ[i])];
		strcpy(g_env[i],environ[i]);
	}
	g_env[i]=NULL;//最后一个元素为NULL
	environ=g_env;//以后维护g_env即可
}


void PrintBaseMassage(){//打印命令行的信息
	printf("[%s]: %s#  ",getenv("USER"),getenv("PWD"));
}

bool GetCommandLine(char* command,int size){
	char *temp=fgets(command,size,stdin);
	if(!temp) return false;
	command[strlen(command)-1]='\0';//处理换行
	if(strlen(command)==0)return false;
	return true;

}

void Getfilename(char* Command,int set){//提取文件名
	int sup=strlen(Command);
	while(set<sup && Command[set++]==' ');
	set--;
	for(int i=set;i<sup;i++){
		if(Command[i]==' ') break;
		filename+=Command[i];
	}

}

bool DivideCommand(char* Command){//分割命令
	if(strlen(Command)==1){
		g_argv[0]=NULL;
		return false;		
	}
	int sup=strlen(Command);
	is_redirect=false;//重置
	filename.clear();
	for(int i=sup;i>=0;i--){//检查是否是重定向，只判断<、>>和>	
		if(Command[i]=='>'){
			is_redirect=true;
			if(i!=0 && Command[i-1]=='>'){
				redirect=">>";
				Getfilename(Command,i+1);
				Command[i-1]='\0';
			}
			else{
				redirect=">";
				Getfilename(Command,i+1);
			}
			Command[i]='\0';
			break;
		}
		else if(Command[i]=='<'){
			is_redirect=true;
			redirect="<";
			Getfilename(Command,i+1);
			Command[i]='\0';
		}
	}

	int i=0;
	g_argv[i++]=strtok(Command," ");
	while(g_argv[i++]=strtok(NULL," "));
	g_argc=i-1;
	return true;
}

bool ExecuteInsideCommand(){//判断内建命令,这里只判断cd,是的话执行并返回true
	if(!strcmp(g_argv[0],"cd")){
		if(g_argc==1 ||chdir(g_argv[1])) cout<<"Cannot find out this path"<<endl;
		return true;
	}
	return false;
}

void ExecuteCommand(){//执行命令
	int pid=fork();
	if(!pid){
		if(is_redirect){
			int fd,iofd;
			if(redirect==">"){
				fd=open(filename.c_str(),O_WRONLY|O_TRUNC|O_CREAT,0776);
				iofd=1;
			}
			else if(redirect==">>"){
				fd=open(filename.c_str(),O_WRONLY|O_APPEND|O_CREAT,0776);
				iofd=1;
			}
			else if(redirect=="<"){
				fd=open(filename.c_str(),O_RDONLY);
				iofd=0;
			}
			else{
				cout<<"Input right symbol"<<endl;
				exit(1);
			}
			if(fd<0){
				cout<<"Cannot find out this file"<<endl;
				exit(1);
			}
			dup2(fd,iofd);
		}
		if(execvpe(g_argv[0],g_argv,g_env)==-1) cout<<"It's failed"<<endl;
		exit(0);
	}
	else {
		int t=0;
		waitpid(pid,&t,0);
	}
}

int main(){
	char Commandtemp[commandnum];//临时存储命令
	EnvironInit();
	while(true){
		PrintBaseMassage();
		if(!GetCommandLine(Commandtemp,commandnum)) continue;
		//直接换行的话就重新来
		if(!DivideCommand(Commandtemp)) continue;
		if(ExecuteInsideCommand()) continue;
		ExecuteCommand();
	}
	return 0;
}
